package com.xbongbong.pro.statistic.service.result;

import com.alibaba.fastjson.JSONObject;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.elasticsearch.pojo.XbbAggregatedPage;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.FundAccountFlowTypeEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.helper.PageHelper;
import com.xbongbong.paas.toolbox.util.Arith;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.toolbox.util.PageHelperUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.pro.constant.I18nStringConstant;
import com.xbongbong.pro.detailtab.pojo.DataDetailTabPojo;
import com.xbongbong.pro.enums.AccessLinkEnum;
import com.xbongbong.pro.enums.SaasMarkEnum;
import com.xbongbong.pro.service.toolbox.statistic.util.ChartResultUtil;
import com.xbongbong.pro.statistic.constant.ChartI18Constant;
import com.xbongbong.pro.statistic.constant.FundStatisticsConstant;
import com.xbongbong.pro.statistic.enums.FundFlowEnum;
import com.xbongbong.pro.statistic.enums.IndicatorRuleEnum;
import com.xbongbong.pro.statistic.enums.NumFormatEnum;
import com.xbongbong.pro.statistic.enums.SystemCodeEnum;
import com.xbongbong.pro.statistic.enums.ValueTypeEnum;
import com.xbongbong.pro.statistic.result.pojo.ChartResultPojo;
import com.xbongbong.pro.statistic.result.pojo.FundFlowInfoPojo;
import com.xbongbong.pro.statistic.result.pojo.vo.ChartResultDetailVO;
import com.xbongbong.pro.statistic.result.pojo.vo.IndexVO;
import com.xbongbong.pro.statistic.result.pojo.vo.ResultTableVO;
import com.xbongbong.pro.statistic.through.pojo.TableDataInfoNewPojo;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.PageConstant;
import com.xbongbong.saas.domain.entity.FundAccountEntity;
import com.xbongbong.saas.domain.entity.FundAccountFlowEntity;
import com.xbongbong.saas.enums.FundAccountFlowEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.FundTransferEnum;
import com.xbongbong.saas.enums.business.OtherExpenseEnum;
import com.xbongbong.saas.enums.business.OtherIncomeEnum;
import com.xbongbong.saas.enums.business.PaySheetEnum;
import com.xbongbong.saas.enums.business.PaymentSheetEnum;
import com.xbongbong.saas.model.FundAccountModel;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * 资金相关统计
 *
 * @author 徐俊杰
 * @version v1.0
 * @date 2020/3/18 9:46
 * @since v1.0
 */
@Service
public class FundResult extends ChartResultParentService implements ChartResultSystem {

    @Resource
    private CrmPaymentResult crmPaymentResult;
    @Resource
    private JxcPayResult jxcPayResult;
    @Resource
    private FundAccountModel fundAccountModel;

    @Override
    public Object getTarget(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        SystemCodeEnum systemCodeEnum = chartResultPojo.getSystemCodeEnum();
        switch (systemCodeEnum) {
            case INCOME_AND_EXPENDITURE:
                return incomeAndExpenditure(chartResultPojo, chartResultDetailVO);
            default:
                break;
        }
        return null;
    }

    @Override
    public Object getValueTarget(ChartResultPojo chartResultPojo) throws XbbException {
        return null;
    }

    /**
     * 资金账户收支情况
     * @param chartResultPojo
     * @param chartResultDetailVO
     * @return java.lang.Object
     * @throws XbbException
     * @author 徐俊杰
     * @since v1.0
     * @version v1.0
     */
    private Object incomeAndExpenditure(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        ResultTableVO resultTableVO = new ResultTableVO();
        String unit = chartResultPojo.getUnit();
        Integer numFormat = chartResultPojo.getNumFormat();
        NumFormatEnum numFormatEnum = NumFormatEnum.getByCode(numFormat);
        //设置title
        List<String> title = Arrays.asList(String.format(I18nMessageUtil.getMessage(ChartI18Constant.FUND_RESULT_TITLE), unit, unit, unit).split(","));
        resultTableVO.setTitle(systemChartHelp.titleNumRight(title));
        //得到筛选时间段内的收入、支出、净流水
        FundFlowInfoPojo fundFlowInfoPojo = getFundFlowInfoPojo(chartResultPojo);
        IndexVO paymentIndex = new IndexVO(fundFlowInfoPojo.getPaymentSheetAmountStr(), FundFlowEnum.PAYMENT.getName(), AccessLinkEnum.PAYMENT_SHEET.getIcon(), AccessLinkEnum.PAYMENT_SHEET.getColor(), unit);
        IndexVO payIndex = new IndexVO(fundFlowInfoPojo.getPaySheetAmountStr(), FundFlowEnum.PAY.getName(), AccessLinkEnum.PAY_SHEET.getIcon(), AccessLinkEnum.PAY_SHEET.getColor(), unit);
        IndexVO flowAmountIndex = new IndexVO(fundFlowInfoPojo.getFlowAmountStr(), FundFlowEnum.FLOW.getName(), AccessLinkEnum.FUND_ACCOUNT.getIcon(), AccessLinkEnum.FUND_ACCOUNT.getColor(), unit);
        //净流水
        double flowAmount = fundFlowInfoPojo.getFlowAmount();
        //以下开始计算期末
        List<Long> accountIdList = chartResultPojo.getAccountIdList();
        Long accountId = accountIdList.get(0);
        //初始账户余额，即用户设置的账户初始金额(总和)
        double initialAmount;
        if (Objects.equals(accountId, FundStatisticsConstant.ALL_ACCOUNT)) {
            //获取该公司资金账户的初始余额总和
            initialAmount = fundAccountModel.sumInitialAmountByCorpid(chartResultPojo.getCorpid());
        } else {
            //当前账户余额-金额
            FundAccountEntity fundAccount = fundAccountModel.getByIdCorpid(accountId, chartResultPojo.getCorpid());
            initialAmount = fundAccount.getInitialAmount().doubleValue();
        }
        //要计算开始时间之前的总回/付款金额，因此开始时间作为结束时间传入
        Integer startTime = chartResultPojo.getStartTime();
        //开始账户余额（全部账户的期初） = 初始账户余额(用户设置) + 开始时间之前的收入金额 - 开始时间之前的支出金额
        double allCountStartAmount = getStartAmount(initialAmount, chartResultPojo, startTime);;
        //期末(即结束账户余额) = 期初（即开始账户余额） + 净流水
        double endAmount = Arith.add(allCountStartAmount, flowAmount);
        String endAmountStr = ChartResultUtil.formatValue2Double(false, ValueTypeEnum.VALUE_MONEY, chartResultPojo.isThousandSwitch(), endAmount, numFormatEnum, chartResultPojo.getNumFormatFlag());
        //期末
        IndexVO endAmountIndex = new IndexVO(endAmountStr, I18nMessageUtil.getMessage(FundStatisticsConstant.END_ACCOUNT), AccessLinkEnum.FUND_ACCOUNT.getIcon(), AccessLinkEnum.FUND_ACCOUNT.getColor(), unit);
        //封装：期末、净流水、回款、付款
        List<IndexVO> indexVOS = Arrays.asList(endAmountIndex, flowAmountIndex, paymentIndex, payIndex);
        //-------------------以下开始封装收支流水列表
        IndexTypeEnum indexTypeEnum = IndexTypeEnum.IDX_FUND_ACCOUNT_FLOW;
        BoolQueryBuilder boolQueryBuilder = chartQueryHelp.fundAccountFlowQuery(chartResultPojo);
        ChartResultUtil.formatPage(chartResultPojo, PageConstant.DEFAULT_PAGE_SIZE_SMALL);
        List<SortBuilder> sortBuilderList = Arrays.asList(new FieldSortBuilder(FundAccountFlowEnum.SHEET_TIME.getAttr()).order(SortOrder.ASC), new FieldSortBuilder(BasicConstant.ID).order(SortOrder.ASC));
        XbbAggregatedPage esEntities = esHelper.findByPage(indexTypeEnum, boolQueryBuilder, FundAccountFlowEntity.class, null, chartResultPojo.getPage(), chartResultPojo.getPageSize(), sortBuilderList);
        List<FundAccountFlowEntity> list = (List<FundAccountFlowEntity>)esEntities.getContent();
        int rowCounts = (int) esEntities.getTotalElements();
        PageHelper pageHelper = PageHelperUtil.initPageHelper(rowCounts, chartResultPojo.getPage(), chartResultPojo.getPageSize(), PageConstant.DEFAULT_PAGE_SIZE);
        resultTableVO.setPageHelper(pageHelper);
        HashSet<Long> accountIdSet = new HashSet<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        //防空处理
        accountIdSet.add(-1L);
        accountIdSet.add(accountId);
        HashSet<Long> paymentSheetIdSet = new HashSet<>(list.size());
        HashSet<Long> paySheetIdSet = new HashSet<>(list.size());
        HashSet<Long> otherIncomeSet = new HashSet<>(list.size());
        HashSet<Long> otherExpenseSet = new HashSet<>(list.size());
        HashSet<Long> fundTransferSet = new HashSet<>(list.size());
        for (FundAccountFlowEntity fundAccountFlowEntity : list) {
            accountIdSet.add(fundAccountFlowEntity.getAccountId());
            Integer type = fundAccountFlowEntity.getType();
            Long sheetId = fundAccountFlowEntity.getSheetId();
            if (Objects.equals(type, FundAccountFlowTypeEnum.PAYMENT_SHEET.getCode())) {
                paymentSheetIdSet.add(sheetId);
            } else if (Objects.equals(type, FundAccountFlowTypeEnum.PAY_SHEET.getCode())) {
                paySheetIdSet.add(sheetId);
            } else if (Objects.equals(type, FundAccountFlowTypeEnum.OTHER_INCOME.getCode())) {
                otherIncomeSet.add(sheetId);
            } else if (Objects.equals(type, FundAccountFlowTypeEnum.OTHER_EXPENSE.getCode())) {
                otherExpenseSet.add(sheetId);
            } else if (Objects.equals(type, FundAccountFlowTypeEnum.FUND_TRANSFER_IN.getCode()) ||
                    Objects.equals(type, FundAccountFlowTypeEnum.FUND_TRANSFER_OUT.getCode())) {
                fundTransferSet.add(sheetId);
            }
        }
        //获取资金账户id-entity的map
        HashMap<String, Object> fundAccountParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        fundAccountParam.put("corpid", chartResultPojo.getCorpid());
        fundAccountParam.put("del", DelEnum.NORMAL.getDel());
        fundAccountParam.put("enable", 1);
        fundAccountParam.put("idIn", accountIdSet);

        List<FundAccountEntity> fundAccountList = fundAccountModel.findEntitys(fundAccountParam);
        HashMap<Long, String> fundAccountIdNameMap = new HashMap<>(fundAccountList.size());
        for (FundAccountEntity fundAccountEntity : fundAccountList) {
            fundAccountIdNameMap.put(fundAccountEntity.getId(), fundAccountEntity.getName());
        }
        //获取回款单id-entity的map
        List<String> paymentSheetField = Arrays.asList("id", "dataId", PaymentSheetEnum.getAttrConnectData(PaymentSheetEnum.AMOUNT), PaymentSheetEnum.SHEET_NO.getAttr(), PaymentSheetEnum.getAttrConnectData(PaymentSheetEnum.CUSTOMER_ID), PaymentSheetEnum.getAttrConnectData(PaymentSheetEnum.CUSTOMER_NAME_LINK_TEXT));
        List<PaasFormDataEntityExt> paymentSheetList = formHelp.getFormListByIds4All(chartResultPojo.getCorpid(), IndexTypeEnum.IDX_SAAS_PAYMENT_SHEET, paymentSheetIdSet, paymentSheetField);
        Map<Long, PaasFormDataEntityExt> paymentSheetIdEntityMap = formHelp.getMap4IdEntity(paymentSheetList);
        //获取付款单id-entity的map
        List<String> paySheetField = Arrays.asList("id", "dataId", PaySheetEnum.getAttrConnectData(PaySheetEnum.AMOUNT), PaySheetEnum.PAY_PLAN_NO.getAttr(), PaySheetEnum.getAttrConnectData(PaySheetEnum.LINK_SUPPLIER), PaySheetEnum.getAttrConnectData(PaySheetEnum.SUPPLIER_LINK_TEXT));
        List<PaasFormDataEntityExt> paySheetList = formHelp.getFormListByIds4All(chartResultPojo.getCorpid(), IndexTypeEnum.IDX_SAAS_PAYPLAN_SHEET, paySheetIdSet, paySheetField);
        Map<Long, PaasFormDataEntityExt> paySheetIdEntityMap = formHelp.getMap4IdEntity(paySheetList);
        //获取其他收入单id-entity的map
        List<String> otherIncomeField = Arrays.asList("id", "dataId", OtherIncomeEnum.getAttrConnectData(OtherIncomeEnum.AMOUNT), OtherIncomeEnum.SHEET_NO.getAttr());
        List<PaasFormDataEntityExt> otherIncomeList = formHelp.getFormListByIds4All(chartResultPojo.getCorpid(), IndexTypeEnum.IDX_SAAS_OTHER_INCOME, otherIncomeSet, otherIncomeField);
        Map<Long, PaasFormDataEntityExt> otherIncomeIdEntityMap = formHelp.getMap4IdEntity(otherIncomeList);
        //获取其他支出单id-entity的map
        List<String> otherExpenseField = Arrays.asList("id", "dataId", OtherExpenseEnum.getAttrConnectData(OtherExpenseEnum.AMOUNT), OtherExpenseEnum.SHEET_NO.getAttr());
        List<PaasFormDataEntityExt> otherExpenseList = formHelp.getFormListByIds4All(chartResultPojo.getCorpid(), IndexTypeEnum.IDX_SAAS_OTHER_EXPENSE, otherExpenseSet, otherExpenseField);
        Map<Long, PaasFormDataEntityExt> otherExpenseIdEntityMap = formHelp.getMap4IdEntity(otherExpenseList);
        //获取资金调拨单id-entity的map
        List<String> fundTransferField = Arrays.asList("id", "dataId", FundTransferEnum.getAttrConnectData(FundTransferEnum.AMOUNT), FundTransferEnum.SHEET_NO.getAttr());
        List<PaasFormDataEntityExt> fundTransferList = formHelp.getFormListByIds4All(chartResultPojo.getCorpid(), IndexTypeEnum.IDX_SAAS_FUND_TRANSFER, fundTransferSet, fundTransferField);
        Map<Long, PaasFormDataEntityExt> fundTransferIdEntityMap = formHelp.getMap4IdEntity(fundTransferList);

        //列表数据包装
        List<List<TableDataInfoNewPojo>> businessData = new ArrayList<>();
        //默认等于全部账户的期初，如果翻页，则计算新一页第一个账户的期初
        double firstStartAmount = allCountStartAmount;
        //如果是第一页之后且有数据的，则要计算第一页之前的回、付款
        if (chartResultPojo.getPage() > BasicConstant.ONE && list.size() > 0) {
            FundAccountFlowEntity fundAccountFlowEntity = list.get(0);
            //当页第一个账户的期初
            firstStartAmount = getAccountStartAmount(initialAmount, chartResultPojo, fundAccountFlowEntity);
        }
        //封装列表数据
        handleTableDate(businessData, list, fundAccountIdNameMap, paymentSheetIdEntityMap, paySheetIdEntityMap, otherIncomeIdEntityMap,
                otherExpenseIdEntityMap, fundTransferIdEntityMap, firstStartAmount, numFormatEnum);
        //加入期初的账户余额数据
        if (Objects.equals(chartResultPojo.getPage(), 1)) {
            String startTimeStr = DateTimeUtil.getStringEpochSecond(startTime.longValue(), DateTimeUtil.SDFDate);
            TableDataInfoNewPojo timePojo = new TableDataInfoNewPojo(startTimeStr);
            TableDataInfoNewPojo accountPojo;
            if (Objects.equals(accountId, FundStatisticsConstant.ALL_ACCOUNT)) {
                accountPojo = new TableDataInfoNewPojo(I18nMessageUtil.getMessage(I18nStringConstant.ALL_ACCOUNTS));
            } else {
                String accountName = fundAccountIdNameMap.get(accountId);
                accountPojo = new TableDataInfoNewPojo(accountName);
            }
            TableDataInfoNewPojo accountBalancePojo = new TableDataInfoNewPojo(StringUtil.formatDouble(ChartResultUtil.formatVal4Num(BigDecimal.valueOf(allCountStartAmount), numFormatEnum)));
            TableDataInfoNewPojo typePojo = new TableDataInfoNewPojo("期初");
            businessData.add(0, Arrays.asList(timePojo, accountPojo, new TableDataInfoNewPojo("--"), new TableDataInfoNewPojo("--"), accountBalancePojo, typePojo, new TableDataInfoNewPojo("--"), new TableDataInfoNewPojo("--")));
        }

        //最后返回数据
        resultTableVO.setBusinessData(businessData);
        resultTableVO.setTableName(I18nMessageUtil.getMessage(IndicatorRuleEnum.INCOME_AND_EXPENDITURE.getName()));
        resultTableVO.setSystemCode(chartResultPojo.getSystemCodeEnum().getSystemCode());
        chartResultDetailVO.setTable(resultTableVO);
        chartResultDetailVO.setIndexVOS(indexVOS);
        return chartResultDetailVO;
    }

    /**
     * 封装返回的表格数据
     * @param businessData
     * @param list
     * @param fundAccountIdNameMap
     * @param paymentSheetIdEntityMap
     * @param paySheetIdEntityMap
     * @param otherIncomeIdEntityMap
     * @param otherExpenseIdEntityMap
     * @param fundTransferIdEntityMap
     * @param firstStartAmount
     * @param numFormatEnum
     */
    private void handleTableDate(List<List<TableDataInfoNewPojo>> businessData, List<FundAccountFlowEntity> list, HashMap<Long, String> fundAccountIdNameMap,
                                 Map<Long, PaasFormDataEntityExt> paymentSheetIdEntityMap, Map<Long, PaasFormDataEntityExt> paySheetIdEntityMap,
                                 Map<Long, PaasFormDataEntityExt> otherIncomeIdEntityMap, Map<Long, PaasFormDataEntityExt> otherExpenseIdEntityMap,
                                 Map<Long, PaasFormDataEntityExt> fundTransferIdEntityMap, double firstStartAmount, NumFormatEnum numFormatEnum) {
        for (FundAccountFlowEntity fundAccountFlowEntity : list) {
            //日期
            Long sheetTime = fundAccountFlowEntity.getSheetTime();
            String sheetTimeStr = DateTimeUtil.getStringEpochSecond(sheetTime, DateTimeUtil.SDFDate);
            TableDataInfoNewPojo timePojo = new TableDataInfoNewPojo(sheetTimeStr);
            //资金账户
            Long accountId1 = fundAccountFlowEntity.getAccountId();
            String accountName = fundAccountIdNameMap.get(accountId1);
            TableDataInfoNewPojo accountPojo = new TableDataInfoNewPojo(accountName);
            //回款金额/付款金额/其他收入单金额/其他支出单金额/资金调拨单金额
            Integer type = fundAccountFlowEntity.getType();
            Long sheetId = fundAccountFlowEntity.getSheetId();
            List<TableDataInfoNewPojo> tableDataInfoNewPojos = new ArrayList<>();
            if (Objects.equals(type, FundAccountFlowTypeEnum.PAYMENT_SHEET.getCode())) {
                PaasFormDataEntityExt paymentSheet = paymentSheetIdEntityMap.get(sheetId);
                if (paymentSheet == null) {
                    continue;
                }
                JSONObject data = paymentSheet.getData();
                //回款金额/付款金额
                double amount = data.getDoubleValue(PaymentSheetEnum.AMOUNT.getAttr());
                TableDataInfoNewPojo paymentAmountPojo = new TableDataInfoNewPojo(StringUtil.formatDouble(ChartResultUtil.formatVal4Num(BigDecimal.valueOf(amount), numFormatEnum)));
                TableDataInfoNewPojo payAmountPojo = new TableDataInfoNewPojo("--");
                //账户余额
                firstStartAmount = Arith.add(firstStartAmount, amount);
                TableDataInfoNewPojo accountBalancePojo = new TableDataInfoNewPojo(StringUtil.formatDouble(ChartResultUtil.formatVal4Num(BigDecimal.valueOf(firstStartAmount), numFormatEnum)));
                //类型
                TableDataInfoNewPojo typePojo = new TableDataInfoNewPojo(XbbRefTypeEnum.PAYMENT_SHEET.getName());
                //编号
                String serialNo = paymentSheet.getSerialNo();
                Long paymentSheetId = paymentSheet.getId();
                TableDataInfoNewPojo numberPojo = new TableDataInfoNewPojo(serialNo, 1, new DataDetailTabPojo(paymentSheetId, SaasMarkEnum.SAAS.getCode(), XbbRefTypeEnum.PAYMENT_SHEET.getCode()));
                //关联客户/供应商
                String customer = data.getString(PaymentSheetEnum.CUSTOMER_NAME_LINK_TEXT.getAttr());
                Long customerId = data.getLongValue(PaymentSheetEnum.CUSTOMER_ID.getAttr());
                TableDataInfoNewPojo customerPojo = new TableDataInfoNewPojo(customer, 1, new DataDetailTabPojo(customerId, SaasMarkEnum.SAAS.getCode(), XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode()));
                tableDataInfoNewPojos = Arrays.asList(timePojo, accountPojo, paymentAmountPojo, payAmountPojo, accountBalancePojo, typePojo, numberPojo, customerPojo);
            } else if (Objects.equals(type, FundAccountFlowTypeEnum.PAY_SHEET.getCode())) {
                PaasFormDataEntityExt paySheet = paySheetIdEntityMap.get(sheetId);
                if (paySheet == null) {
                    continue;
                }
                JSONObject data = paySheet.getData();
                //回款金额/付款金额
                double amount = data.getDoubleValue(PaySheetEnum.AMOUNT.getAttr());
                TableDataInfoNewPojo paymentAmountPojo = new TableDataInfoNewPojo("--");
                TableDataInfoNewPojo payAmountPojo = new TableDataInfoNewPojo(StringUtil.formatDouble(ChartResultUtil.formatVal4Num(BigDecimal.valueOf(amount), numFormatEnum)));
                //账户余额
                firstStartAmount = Arith.sub(firstStartAmount, amount);
                TableDataInfoNewPojo accountBalancePojo = new TableDataInfoNewPojo(StringUtil.formatDouble(ChartResultUtil.formatVal4Num(BigDecimal.valueOf(firstStartAmount), numFormatEnum)));
                //类型
                TableDataInfoNewPojo typePojo = new TableDataInfoNewPojo(XbbRefTypeEnum.PAY_SHEET.getName());
                //编号
                String serialNo = paySheet.getSerialNo();
                Long paymentSheetId = paySheet.getId();
                TableDataInfoNewPojo numberPojo = new TableDataInfoNewPojo(serialNo, 1, new DataDetailTabPojo(paymentSheetId, SaasMarkEnum.SAAS.getCode(), XbbRefTypeEnum.PAY_SHEET.getCode()));
                //关联客户/供应商
                String supplier = data.getString(PaySheetEnum.SUPPLIER_LINK_TEXT.getAttr());
                Long supplierId = data.getLongValue(PaySheetEnum.LINK_SUPPLIER.getAttr());
                TableDataInfoNewPojo supplierPojo = new TableDataInfoNewPojo(supplier, 1, new DataDetailTabPojo(supplierId, SaasMarkEnum.SAAS.getCode(), XbbRefTypeEnum.SUPPLIER.getCode()));
                tableDataInfoNewPojos = Arrays.asList(timePojo, accountPojo, paymentAmountPojo, payAmountPojo, accountBalancePojo, typePojo, numberPojo, supplierPojo);
            } else if (Objects.equals(type, FundAccountFlowTypeEnum.OTHER_INCOME.getCode())) {
                PaasFormDataEntityExt otherIncome = otherIncomeIdEntityMap.get(sheetId);
                if (Objects.isNull(otherIncome)) {
                    continue;
                }
                JSONObject data = otherIncome.getData();
                //其他收入单金额
                double amount = data.getDoubleValue(OtherIncomeEnum.AMOUNT.getAttr());
                TableDataInfoNewPojo paymentAmountPojo = new TableDataInfoNewPojo(StringUtil.formatDouble(ChartResultUtil.formatVal4Num(BigDecimal.valueOf(amount), numFormatEnum)));
                TableDataInfoNewPojo payAmountPojo = new TableDataInfoNewPojo("--");
                //账户余额
                firstStartAmount = Arith.add(firstStartAmount, amount);
                TableDataInfoNewPojo accountBalancePojo = new TableDataInfoNewPojo(StringUtil.formatDouble(ChartResultUtil.formatVal4Num(BigDecimal.valueOf(firstStartAmount), numFormatEnum)));
                //类型
                TableDataInfoNewPojo typePojo = new TableDataInfoNewPojo(FundAccountFlowTypeEnum.OTHER_INCOME.getName());
                //编号
                String serialNo = otherIncome.getSerialNo();
                Long otherIncomeId = otherIncome.getId();
                TableDataInfoNewPojo numberPojo = new TableDataInfoNewPojo(serialNo, 1, new DataDetailTabPojo(otherIncomeId, SaasMarkEnum.SAAS.getCode(), XbbRefTypeEnum.OTHER_INCOME.getCode()));
                TableDataInfoNewPojo supplierPojo = new TableDataInfoNewPojo("--");
                tableDataInfoNewPojos = Arrays.asList(timePojo, accountPojo, paymentAmountPojo, payAmountPojo, accountBalancePojo, typePojo, numberPojo, supplierPojo);
            } else if (Objects.equals(type, FundAccountFlowTypeEnum.OTHER_EXPENSE.getCode())) {
                PaasFormDataEntityExt otherExpense = otherExpenseIdEntityMap.get(sheetId);
                if (Objects.isNull(otherExpense)) {
                    continue;
                }
                JSONObject data = otherExpense.getData();
                //其他支出单金额
                double amount = data.getDoubleValue(OtherExpenseEnum.AMOUNT.getAttr());
                TableDataInfoNewPojo paymentAmountPojo = new TableDataInfoNewPojo(StringUtil.formatDouble(ChartResultUtil.formatVal4Num(BigDecimal.valueOf(amount), numFormatEnum)));
                TableDataInfoNewPojo payAmountPojo = new TableDataInfoNewPojo("--");
                //账户余额
                firstStartAmount = Arith.sub(firstStartAmount, amount);
                TableDataInfoNewPojo accountBalancePojo = new TableDataInfoNewPojo(StringUtil.formatDouble(ChartResultUtil.formatVal4Num(BigDecimal.valueOf(firstStartAmount), numFormatEnum)));
                //类型
                TableDataInfoNewPojo typePojo = new TableDataInfoNewPojo(FundAccountFlowTypeEnum.OTHER_EXPENSE.getName());
                //编号
                String serialNo = otherExpense.getSerialNo();
                Long otherExpenseId = otherExpense.getId();
                TableDataInfoNewPojo numberPojo = new TableDataInfoNewPojo(serialNo, 1, new DataDetailTabPojo(otherExpenseId, SaasMarkEnum.SAAS.getCode(), XbbRefTypeEnum.OTHER_EXPENSE.getCode()));
                TableDataInfoNewPojo supplierPojo = new TableDataInfoNewPojo("--");
                tableDataInfoNewPojos = Arrays.asList(timePojo, accountPojo, payAmountPojo, paymentAmountPojo, accountBalancePojo, typePojo, numberPojo, supplierPojo);
            } else if (Objects.equals(type, FundAccountFlowTypeEnum.FUND_TRANSFER_IN.getCode()) || Objects.equals(type, FundAccountFlowTypeEnum.FUND_TRANSFER_OUT.getCode())) {
                PaasFormDataEntityExt fundTransfer = fundTransferIdEntityMap.get(sheetId);
                if (Objects.isNull(fundTransfer)) {
                    continue;
                }
                JSONObject data = fundTransfer.getData();
                //其他收入单金额
                double amount = data.getDoubleValue(FundTransferEnum.AMOUNT.getAttr());
                //账户余额
                TableDataInfoNewPojo paymentAmountPojo = null;
                TableDataInfoNewPojo payAmountPojo = null;
                if (Objects.equals(type, FundAccountFlowTypeEnum.FUND_TRANSFER_IN.getCode())) {
                    firstStartAmount = Arith.add(firstStartAmount, amount);
                    paymentAmountPojo = new TableDataInfoNewPojo(StringUtil.formatDouble(ChartResultUtil.formatVal4Num(BigDecimal.valueOf(amount), numFormatEnum)));
                    payAmountPojo = new TableDataInfoNewPojo("--");
                }else {
                    firstStartAmount = Arith.sub(firstStartAmount, amount);
                    payAmountPojo = new TableDataInfoNewPojo(StringUtil.formatDouble(ChartResultUtil.formatVal4Num(BigDecimal.valueOf(amount), numFormatEnum)));
                    paymentAmountPojo = new TableDataInfoNewPojo("--");
                }
                TableDataInfoNewPojo accountBalancePojo = new TableDataInfoNewPojo(StringUtil.formatDouble(ChartResultUtil.formatVal4Num(BigDecimal.valueOf(firstStartAmount), numFormatEnum)));
                //类型
                TableDataInfoNewPojo typePojo = new TableDataInfoNewPojo(FundAccountFlowTypeEnum.FUND_TRANSFER_IN.getName());
                //编号
                String serialNo = fundTransfer.getSerialNo();
                Long fundTransferId = fundTransfer.getId();
                TableDataInfoNewPojo numberPojo = new TableDataInfoNewPojo(serialNo, 1, new DataDetailTabPojo(fundTransferId, SaasMarkEnum.SAAS.getCode(), XbbRefTypeEnum.FUND_TRANSFER.getCode()));
                TableDataInfoNewPojo supplierPojo = new TableDataInfoNewPojo("--");
                tableDataInfoNewPojos = Arrays.asList(timePojo, accountPojo, paymentAmountPojo, payAmountPojo, accountBalancePojo, typePojo, numberPojo, supplierPojo);
            }
            businessData.add(tableDataInfoNewPojos);
        }
    }

    /**
     * 得到全部账户的期初
     * @param initialAmount 账户的初始金额
     * @param chartResultPojo 查询条件pojo
     * @param endTime 结束时间
     * @return double
     * @throws XbbException
     * @author zcp
     * @since v1.0
     * @version v1.0
     */
    private double getStartAmount(double initialAmount, ChartResultPojo chartResultPojo, Integer endTime) throws XbbException {
        ChartResultPojo chartResultPojoBefore = new ChartResultPojo();
        BeanUtil.copyProperties(chartResultPojo, chartResultPojoBefore);
        chartResultPojoBefore.setStartTime(0);
        chartResultPojoBefore.setEndTime(endTime);
        double paymentSheetAmountBefore = crmPaymentResult.paymentSheet4FundAccount(chartResultPojoBefore);
        double paySheetAmountBefore = jxcPayResult.paySheet4FundAccount(chartResultPojoBefore);
        /*
         开始账户余额 = 初始账户余额(用户设置) + 开始时间之前的回款单金额 - 开始时间之前的付款单金额
         其中，
             开始账户余额：如果在第一页，则为全部账户的期初；如果不在第一页，则为当页第一个账户的期初(需±其本身的回/付款金额后即为其账户余额)
             初始账户余额：即用户设置的账户初始金额(总和)
             开始时间之前的回/付款单金额：查询时不限制数据的开始时间，直接条件内的startTime作为条件的endTime进行封装条件
         */
        return Arith.sub(Arith.add(initialAmount, paymentSheetAmountBefore), paySheetAmountBefore);
    }

    /**
     * 得到当页第一条流水之前的所有流水总的sheetAmount：回/付款金额（付款金额已经取反处理）
     * @param initialAmount 账户初始金额
     * @param chartResultPojo 筛选条件
     * @param pageFirstfundAccountFlowEntity 资金流水实体
     * @return double
     * @throws XbbException
     * @author zcp
     * @since v1.0
     * @version v1.0
     */
    private double getAccountStartAmount(double initialAmount, ChartResultPojo chartResultPojo, FundAccountFlowEntity pageFirstfundAccountFlowEntity) throws XbbException {
        /*
         ①得到当前页第一条数据的sheetTime及其flowId；
         ②聚合得到 小于sheetTime or 等于sheetTime且流水id小于flowId的总sheetAmount
            a、不能直接用小于等于sheetTime且流水id小于flowId，因为flowId并不是直接排序的关键字段，只是作为辅助字段进行排序（当sheetTime一致时，用flowId进行排序）
            b、处理该步需保证流水排序是按照 sheetTime asc，id asc；如果不是该排序，则计算其他流水的余额时加减做相应处理即可
         ③上一步得到的sheetAmount值最后再加上账户的初始金额，即得到当前页第一个账户的账户余额；
         ④该页其他数据直接用上一个账户余额，±流水sheetAmount计算得到即可。
         */
        Long flowId = pageFirstfundAccountFlowEntity.getId();
        Long sheetTime = pageFirstfundAccountFlowEntity.getSheetTime();
        /*--------处理查询条件--------*/
        BoolQueryBuilder beforeQueryBuilder = chartQueryHelp.fundAccountFlowQuery4PageFirstBefore(chartResultPojo, sheetTime, flowId);
        //对应②
        double beforeSheetAmount = systemChartHelp.getDouble4Total(IndexTypeEnum.IDX_FUND_ACCOUNT_FLOW, beforeQueryBuilder, "sheetAmount");
        //对应③，最后④在该方法外部基于该方法返回值计算即可
        return Arith.add(initialAmount, beforeSheetAmount);
    }

    /**
     * 得到账户的回款、付款、净流水值
     * @param chartResultPojo
     * @return com.xbongbong.pro.statistic.result.pojo.FundFlowInfoPojo
     * @throws XbbException
     * @author zcp
     * @since v1.0
     * @version v1.0
     */
    public FundFlowInfoPojo getFundFlowInfoPojo(ChartResultPojo chartResultPojo) throws XbbException {
        NumFormatEnum numFormatEnum = NumFormatEnum.getByCode(chartResultPojo.getNumFormat());
        //收入
        double paymentSheetAmount = crmPaymentResult.paymentSheet4FundAccount(chartResultPojo);
        String paymentSheetAmountStr = ChartResultUtil.formatValue2Double(false, ValueTypeEnum.VALUE_MONEY, chartResultPojo.isThousandSwitch(), paymentSheetAmount, numFormatEnum, chartResultPojo.getNumFormatFlag());
        //支出
        double paySheetAmount = jxcPayResult.paySheet4FundAccount(chartResultPojo);
        String paySheetAmountStr = ChartResultUtil.formatValue2Double(false, ValueTypeEnum.VALUE_MONEY, chartResultPojo.isThousandSwitch(), paySheetAmount, numFormatEnum, chartResultPojo.getNumFormatFlag());
        //净流水
        double flowAmount = Arith.sub(paymentSheetAmount, paySheetAmount);
        String flowAmountStr = ChartResultUtil.formatValue2Double(false, ValueTypeEnum.VALUE_MONEY, chartResultPojo.isThousandSwitch(), flowAmount, numFormatEnum, chartResultPojo.getNumFormatFlag());

        return new FundFlowInfoPojo(paymentSheetAmount, paymentSheetAmountStr, paySheetAmount, paySheetAmountStr, flowAmount, flowAmountStr);
    }
}
